using System;
using System.Collections.Generic;
using System.Text;
using ScrewTurn.Wiki.PluginFramework;
using ScrewTurn.Wiki;
using System.Text.RegularExpressions;

namespace Stankovski.Wiki.FormattingPlus
{
	public class TableFormatter : FormatterPlusBase
	{
		private static Regex table = new Regex(@"\{\|(\ [^\n]*)?\n(.|\n|\r)+?\|\}", RegexOptions.Compiled | RegexOptions.Singleline);

		public override string Format(string raw, ContextInformation context, FormattingPhase phase)
		{
			if (phase != FormattingPhase.Phase1)
				return raw;

			StringBuilder sb = new StringBuilder(raw);
			List<int> noWikiBegin = new List<int>(), noWikiEnd = new List<int>();
			int end = 0;
			ComputeNoWiki(sb.ToString(), ref noWikiBegin, ref noWikiEnd);
			
			Match match = table.Match(sb.ToString());
			while (match.Success)
			{
				if (!IsNoWikied(match.Index, noWikiBegin, noWikiEnd, out end))
				{
					sb.Remove(match.Index, match.Length);
					sb.Insert(match.Index, buildTable(match.Value, context, phase));
				}
				ComputeNoWiki(sb.ToString(), ref noWikiBegin, ref noWikiEnd);
				match = table.Match(sb.ToString(), end);
			}
			return sb.ToString();
		}

		/// <summary>
		/// Builds a HTML table from WikiMarkup.
		/// </summary>
		/// <param name="table">The WikiMarkup.</param>
		/// <returns>The HTML.</returns>
		private string buildTable(string table, ContextInformation context, FormattingPhase phase)
		{
			// Proceed line-by-line, ignoring the first and last one
			string[] lines = table.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
			if (lines.Length < 3)
			{
				return "<b>FORMATTER ERROR (Malformed Table)</b>";
			}
			StringBuilder sb = new StringBuilder();
			sb.Append("<table");
			if (lines[0].Length > 2)
			{
				sb.Append(" ");
				sb.Append(lines[0].Substring(3));
			}
			sb.Append(">");
			int count = 1;
			if (lines[1].Length >= 3 && lines[1].Trim().StartsWith("|+"))
			{
				// Table caption
				sb.Append("<caption>");
				sb.Append(lines[1].Substring(3));
				sb.Append("</caption>");
				count++;
			}
			if (!lines[count].StartsWith("|-")) sb.Append("<tr>");
			string item;
			for (int i = count; i < lines.Length - 1; i++)
			{
				if (lines[i].Trim().StartsWith("|-"))
				{
					// New line
					if (i != count) sb.Append("</tr>");
					sb.Append("<tr");
					if (lines[i].Length > 2)
					{
						sb.Append(" ");
						sb.Append(lines[i].Substring(3));
					}
					sb.Append(">");
				}
				else if (lines[i].Trim().StartsWith("|"))
				{
					// Cell
					if (lines[i].Length < 3) continue;
					item = lines[i].Substring(2);
					if (item.IndexOf(" || ") != -1)
					{
						sb.Append("<td>");
						sb.Append(item.Replace(" || ", "</td><td>"));
						sb.Append("</td>");
					}
					else if (item.IndexOf(" | ") != -1)
					{
						sb.Append("<td ");
						sb.Append(item.Substring(0, item.IndexOf(" | ")));
						sb.Append(">");
						sb.Append(item.Substring(item.IndexOf(" | ") + 3));
						sb.Append("</td>");
					}
					else
					{
						sb.Append("<td>");
						StringBuilder sbCell = new StringBuilder(item);
						while (i < lines.Length - 2)
						{
							if (!lines[i + 1].Trim().StartsWith("|"))
							{
								i++;
								sbCell.Append("\n" + lines[i]);
							}
							else
							{
								break;
							}
						}
						sb.Append(Formatter.Format(sbCell.ToString(), false, FormattingContext.MessageBody, context.Page));
						sb.Append("</td>");
					}
				}
				else if (lines[i].Trim().StartsWith("!"))
				{
					// Header
					if (lines[i].Length < 3) continue;
					item = lines[i].Substring(2);
					if (item.IndexOf(" !! ") != -1)
					{
						sb.Append("<th>");
						sb.Append(item.Replace(" !! ", "</th><th>"));
						sb.Append("</th>");
					}
					else if (item.IndexOf(" ! ") != -1)
					{
						sb.Append("<th ");
						sb.Append(item.Substring(0, item.IndexOf(" ! ")));
						sb.Append(">");
						sb.Append(item.Substring(item.IndexOf(" ! ") + 3));
						sb.Append("</th>");
					}
					else
					{
						sb.Append("<th>");
						sb.Append(item);
						sb.Append("</th>");
					}
				}
			}
			if (sb.ToString().EndsWith("<tr>"))
			{
				sb.Remove(sb.Length - 4 - 1, 4);
				sb.Append("</table>");
			}
			else
			{
				sb.Append("</tr></table>");
			}
			sb.Replace("<tr></tr>", "");

			return sb.ToString();
		}
	}
}
